package com.rla.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rla.common.constant.Globebill;
import com.rla.common.constant.OrderConstants;
import com.rla.common.utils.SecurityUtils;
import com.rla.common.utils.lqlUtils;
import com.rla.domain.*;
import com.rla.domain.bo.MallOrderBo;
import com.rla.domain.vo.MallOrderPayVo;
import com.rla.domain.vo.MallOrderVo;
import com.rla.domain.vo.VipUserInfoVo;
import com.rla.mapper.*;
import com.rla.service.IMallOrderDetailService;
import com.rla.service.IMallOrderOnlinePayService;
import com.rla.service.IMallOrderPayService;
import com.rla.service.IMallOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@RequiredArgsConstructor
@Service
public class MallOrderOnlinePayServiceImpl implements IMallOrderOnlinePayService {

    private final MallOnlinePayWechatCallbackMapper mallOnlinePayWechatCallbackMapper;
    private final IMallOrderService mallOrderService;
    private final MallOrderPayMapper mallOrderPayMapper;
    private final VipUserInfoMapper vipUserInfoMapper;
    private final VipUserBalanceDetailMapper vipUserBalanceDetailMapper;

    @Override
    public Map<String, Object> lqlPay(JSONObject jo, String api) {

        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String json = jo.toJSONString();
        String signVal = lqlUtils.sign256(json, Globebill.DevPrivateKey);//SHA256withRSA签名
        String url = Globebill.server + api;
        HashMap<String, String> headers = new HashMap<>();
        HashMap<String, String> responseHeaders = new HashMap<>();
        String timestamp = sdf2.format(new Date());
        headers.put("AccessId", "4088");
        headers.put("Timestamp", timestamp);
        headers.put("SignType", Globebill.SIGNATURE_ALGORITHM);
        headers.put("SignValue", signVal);
        String respStr = lqlUtils.httpPost(url, json, headers, responseHeaders);

        Map<String, Object> map = JSON.parseObject(respStr, new TypeReference<Map<String, Object>>() {
        });

        System.out.println(responseHeaders.toString());
        String sigValRsp = responseHeaders.get("SignValue");
        if (sigValRsp != null && sigValRsp.length() > 0) {
            boolean verify = lqlUtils.verify256(respStr, sigValRsp, Globebill.QBPublicKey);
            System.out.println("验签结果：" + verify);
        }

        return map;
    }

    //回调三方结果存到微信支付回调表，修改订单状态，订单支付表
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lqlNotifyCallback(Map<String, String> map) {

        //煞笔三方支付一直回调多次回调，导致回调记录表出现重复数据。TODO 后续回调不到，可放队列主动请求支付结果
        List<MallOnlinePayWechatCallback> mallOnlinePayWechatCallbacks = mallOnlinePayWechatCallbackMapper.selectList(Wrappers.lambdaUpdate(MallOnlinePayWechatCallback.class)
                .eq(MallOnlinePayWechatCallback::getOrderId, map.get("outTransId"))
                .eq(MallOnlinePayWechatCallback::getTransactionId, map.get("tradeId")));

        if (mallOnlinePayWechatCallbacks.isEmpty()) {
            MallOnlinePayWechatCallback callback = new MallOnlinePayWechatCallback();
            MallOrderBo mallOrderBo = new MallOrderBo();
            //支付成功 写入到回调表、更改订单状态
            if (ObjectUtil.isNotEmpty(map) && map.get("tradeStatus").equals("SUCCESS")) {
                callback.setOrderId(map.get("outTransId"));
                callback.setTransactionId(map.get("tradeId"));
                callback.setTradeState(map.get("tradeStatus"));
                callback.setPayerTotal(Long.parseLong(map.get("tradeAmount")));
                callback.setSuccessTime(map.get("payTime"));
                callback.setTradeStateDesc(map.toString());

                mallOrderBo.setId(map.get("outTransId"));
                mallOrderBo.setOrderStatus(OrderConstants.PENDING_SHIPMENT);
                mallOrderBo.setOnlinePayTime(DateUtil.now());


                mallOrderService.updateByBo(mallOrderBo);
                mallOrderPayMapper.update(null, Wrappers.lambdaUpdate(MallOrderPay.class)
                                .set(MallOrderPay::getPaymentTime, map.get("payTime"))
                                .set(MallOrderPay::getRemark, map.get("tradeId"))
                                .set(MallOrderPay::getExpandJson, map.toString())
                                .eq(MallOrderPay::getOrderId, map.get("outTransId"))
                                .eq(MallOrderPay::getPayMode, OrderConstants.WECHAT)
                );
                mallOnlinePayWechatCallbackMapper.insert(callback);

                //判断是否有储值支付（组合支付），有储值先去冻结
                if("1".equals(map.get("tradeType"))){//消费
                    this.balanceConsumption(map.get("outTransId"));
                }
            }

        } else {
            //TODO 不知道失败返回什么信息，（不支付也不知道，先调三方支付返回信息微信支付，关闭支付没有回调）

        }

    }


    /*
    *
    * 退款
    * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean  orderRefund(String userId, String orderId, BigDecimal tradeAmount, String payId,String flag,Map<String,Object> map){

        int a=0;
        int b=0;
        int c=0;
        if(flag.equals(OrderConstants.BALANCE)){
            //用户储值余额解冻增加可用累计
            VipUserInfoVo vipUserInfoVo = vipUserInfoMapper.selectVoById(userId);
            BigDecimal sumBalance = vipUserInfoVo.getSumBalance().add(tradeAmount);
            BigDecimal usableBalance = vipUserInfoVo.getUsableBalance().add(tradeAmount);
            BigDecimal freezeBalance = vipUserInfoVo.getFreezeBalance().subtract(tradeAmount);
            a = vipUserInfoMapper.update(null, Wrappers.lambdaUpdate(VipUserInfo.class)
                    .set(VipUserInfo::getSumBalance, sumBalance)
                    .set(VipUserInfo::getUsableBalance, usableBalance)
                    .set(VipUserInfo::getFreezeBalance, freezeBalance)
                    .eq(VipUserInfo::getId, userId)
            );

            //TODO 记录储蓄金消费明细
            VipUserBalanceDetail vipUserBalanceDetail = new VipUserBalanceDetail();
            vipUserBalanceDetail.setUserId(userId);
            vipUserBalanceDetail.setBalanceType(OrderConstants.REFUND);
            vipUserBalanceDetail.setChangeAmount(tradeAmount);
            vipUserBalanceDetail.setChangeTime(new Date());
            vipUserBalanceDetail.setDetailCode(orderId);
            vipUserBalanceDetail.setCreateTime(new Date());
            vipUserBalanceDetail.setUpdateTime(new Date());
            vipUserBalanceDetail.setCreateBy(userId);
            vipUserBalanceDetail.setUpdateBy(userId);
            vipUserBalanceDetail.setBeforeBalance(vipUserInfoVo.getUsableBalance());
            vipUserBalanceDetail.setAfterBalance(usableBalance);
            vipUserBalanceDetailMapper.insert(vipUserBalanceDetail);
        }else if(flag.equals(OrderConstants.WECHAT)){
            Map<String, Object> result = BeanUtil.beanToMap(map.get("result"));
            MallOnlinePayWechatCallback callback = new MallOnlinePayWechatCallback();
            callback.setOrderId(result.get("outTransId").toString());
            callback.setTransactionId(result.get("tradeId").toString());
            callback.setTradeState(result.get("tradeStatus").toString());
            callback.setPayerTotal(Long.parseLong(result.get("tradeAmount").toString()));
            callback.setTradeStateDesc(result.toString());
            b = mallOnlinePayWechatCallbackMapper.insert(callback);
        }


        //更新支付信息，退款金额等
        MallOrderPay mallOrderPay = new MallOrderPay();
        mallOrderPay.setId(payId);
        mallOrderPay.setBackAmount(tradeAmount);
        c = mallOrderPayMapper.updateById(mallOrderPay);
        return a>0 && b>0 && c>0;
    }


    /*
     *
     * 储值消费
     * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean  balanceConsumption(String orderId){

        MallOrderVo orderVo = mallOrderService.queryById(orderId);

        List<MallOrderPayVo> payList = mallOrderPayMapper.selectVoList(Wrappers.lambdaUpdate(MallOrderPay.class).eq(MallOrderPay::getOrderId, orderId));
        BigDecimal payAmount = BigDecimal.ZERO;
        Boolean flag = false;
        for (MallOrderPayVo vo : payList) {
            if (vo.getPayMode().equals(OrderConstants.BALANCE)){
                flag = true;
                payAmount=vo.getPaymentAmount();
            }
        }

        //有储值支付方式，需要去储值扣款
        if (flag){
            //用户储值余额解冻增加可用累计
            VipUserInfoVo vipUserInfoVo = vipUserInfoMapper.selectVoById(orderVo.getUserId());
            BigDecimal sumBalance = vipUserInfoVo.getSumBalance().subtract(payAmount);
            BigDecimal usableBalance = vipUserInfoVo.getUsableBalance().subtract(payAmount);
            BigDecimal freezeBalance = vipUserInfoVo.getFreezeBalance().add(payAmount);
            int a = vipUserInfoMapper.update(null, Wrappers.lambdaUpdate(VipUserInfo.class)
                    .set(VipUserInfo::getSumBalance, sumBalance)
                    .set(VipUserInfo::getUsableBalance, usableBalance)
                    .set(VipUserInfo::getFreezeBalance, freezeBalance)
                    .eq(VipUserInfo::getId, orderVo.getUserId())
            );

            VipUserBalanceDetail vipUserBalanceDetail = new VipUserBalanceDetail();
            vipUserBalanceDetail.setUserId(orderVo.getUserId());
            vipUserBalanceDetail.setBalanceType(OrderConstants.SHIPPING);
            vipUserBalanceDetail.setChangeAmount(payAmount.negate());
            vipUserBalanceDetail.setChangeTime(new Date());
            vipUserBalanceDetail.setDetailCode(orderId);
            vipUserBalanceDetail.setCreateBy(orderVo.getUserId());
            vipUserBalanceDetail.setCreateTime(new Date());
            vipUserBalanceDetail.setUpdateBy(orderVo.getUserId());
            vipUserBalanceDetail.setUpdateTime(new Date());
            vipUserBalanceDetail.setVipLevel(vipUserInfoVo.getVipGradeCode());
            vipUserBalanceDetail.setBeforeBalance(vipUserInfoVo.getUsableBalance());
            vipUserBalanceDetail.setAfterBalance(usableBalance);
            vipUserBalanceDetailMapper.insert(vipUserBalanceDetail);
            return a>0 ;
        }else{
            return true;
        }

    }


}
